/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.modpircbot;

/**
 *
 * @author tangd
 */

import org.jibble.pircbot.*;
import java.io.*;
import java.util.*;
import org.jsoup.select.Elements;
import org.modpircbot.callback.*;
import java.net.InetAddress;

public class ModPircbot extends PircBot{
    public static final int RPL_ISUPPORT = 5;
    private ModPircbot mainBot;
    private ArrayList<Handler> modules = new ArrayList<Handler>();
    private boolean useDefaultModeParsing = false;
    //private ArrayList<HashSet<String>> supportedModes = new ArrayList<HashSet<String>>();
    private HashMap<String, Integer> supportedModes = new HashMap<String, Integer>();
    //<editor-fold desc="Lots and lots of arraylists for handlers" defaultstate="collapsed">
    public ArrayList<ActionHandler> actionHandlers = new ArrayList<ActionHandler>();
    public ArrayList<ChannelInfoHandler> channelInfoHandlers = new ArrayList<ChannelInfoHandler>();
    public ArrayList<ChannelModeHandler> channelModeHandlers = new ArrayList<ChannelModeHandler>();
    public ArrayList<ConnectHandler> connectHandlers = new ArrayList<ConnectHandler>();
    public ArrayList<DccChatHandler> dccChatHandlers = new ArrayList<DccChatHandler>();
    public ArrayList<DccSendHandler> dccSendHandlers = new ArrayList<DccSendHandler>();
    public ArrayList<DeHalfOpHandler> deHalfopHandlers = new ArrayList<DeHalfOpHandler>();
    public ArrayList<DeOpHandler> deOpHandlers = new ArrayList<DeOpHandler>();
    public ArrayList<DeVoiceHandler> deVoiceHandlers = new ArrayList<DeVoiceHandler>();
    public ArrayList<DisconnectHandler> disconnectHandlers = new ArrayList<DisconnectHandler>();
    public ArrayList<FileTransferFinishedHandler> fileTransferFinishedHandlers = new ArrayList<FileTransferFinishedHandler>();
    public ArrayList<FingerHandler> fingerHandlers = new ArrayList<FingerHandler>();
    public ArrayList<HalfOpHandler> halfOpHandlers = new ArrayList<HalfOpHandler>();
    public ArrayList<IncomingChatReqHandler> incomingChatReqHandlers = new ArrayList<IncomingChatReqHandler>();
    public ArrayList<IncomingFileTransferHander> incomingFileTransferHandlers = new ArrayList<IncomingFileTransferHander>();
    public ArrayList<InviteHandler> inviteHandlers = new ArrayList<InviteHandler>();
    public ArrayList<JoinHandler> joinHandlers = new ArrayList<JoinHandler>();
    public ArrayList<KickHandler> kickHandlers = new ArrayList<KickHandler>();
    public ArrayList<MessageHandler> messageHandlers= new ArrayList<MessageHandler>();
    public ArrayList<NickChangeHandler> nickChangeHandlers = new ArrayList<NickChangeHandler>();
    public ArrayList<NoticeHandler> noticeHandlers = new ArrayList<NoticeHandler>();
    public ArrayList<OpHandler> opHandlers = new ArrayList<OpHandler>();
    public ArrayList<PartHandler> partHandlers = new ArrayList<PartHandler>();
    public ArrayList<PingHandler> pingHandlers = new ArrayList<PingHandler>();
    public ArrayList<PrivateMessageHandler> privateMessageHandlers = new ArrayList<PrivateMessageHandler>();
    public ArrayList<QuitHandler> quitHandlers = new ArrayList<QuitHandler>();
    public ArrayList<RemoveChannelBanHandler> removeChannelBanHandlers = new ArrayList<RemoveChannelBanHandler>();
    public ArrayList<RemoveChannelKeyHandler> removeChannelKeyHandlers= new ArrayList<RemoveChannelKeyHandler>();
    public ArrayList<RemoveChannelLimitHandler> removeChannelLimitHandlers = new ArrayList<RemoveChannelLimitHandler>();
    public ArrayList<RemoveInviteHandler> removeInviteHandlers= new ArrayList<RemoveInviteHandler>();
    public ArrayList<RemoveModeratedHandler> removeModeratedHandlers = new ArrayList<RemoveModeratedHandler>();
    public ArrayList<RemoveNoExternalMessagesHandler> removeNoExternalMessagesHandlers = new ArrayList<RemoveNoExternalMessagesHandler>();
    public ArrayList<RemovePrivateHandler> removePrivateHandlers = new ArrayList<RemovePrivateHandler>();
    public ArrayList<RemoveSecretHandler> removeSecretHandlers = new ArrayList<RemoveSecretHandler>();
    public ArrayList<RemoveTopicProtectionHandler> removeTopicProtectionHandlers = new ArrayList<RemoveTopicProtectionHandler>();
    public ArrayList<ServerPingHandler> serverPingHandlers = new ArrayList<ServerPingHandler>();
    public ArrayList<ServerResponseHandler> serverResponseHandlers = new ArrayList<ServerResponseHandler>();
    public ArrayList<SetChannelBanHandler> setChannelBanHandlers = new ArrayList<SetChannelBanHandler>();
    public ArrayList<SetChannelKeyHandler> setChannelKeyHandlers = new ArrayList<SetChannelKeyHandler>();
    public ArrayList<SetChannelLimitHandler> setChannelLimitHandlers = new ArrayList<SetChannelLimitHandler>();
    public ArrayList<SetInviteOnlyHandler> setInviteOnlyHandlers = new ArrayList<SetInviteOnlyHandler>();
    public ArrayList<SetModeratedHandler> setModeratedHandlers = new ArrayList<SetModeratedHandler>();
    public ArrayList<SetNoExternalMessagesHandler> setNoExternalMessagesHandlers= new ArrayList<SetNoExternalMessagesHandler>();
    public ArrayList<SetPrivateHandler> setPrivateHandlers = new ArrayList<SetPrivateHandler>();
    public ArrayList<SetSecretHandler> setSecretHandlers= new ArrayList<SetSecretHandler>();
    public ArrayList<SetTopicProtectionHandler> setTopicProtectionHandlers = new ArrayList<SetTopicProtectionHandler>();
    public ArrayList<TimeHandler> timeHandlers = new ArrayList<TimeHandler>();
    public ArrayList<TopicHandler> topicHandlers = new ArrayList<TopicHandler>();
    public ArrayList<UserListHandler> userListHandlers= new ArrayList<UserListHandler>();
    public ArrayList<UserModeHandler> userModeHandlers= new ArrayList<UserModeHandler>();
    public ArrayList<VersionHandler> versionHandlers= new ArrayList<VersionHandler>();
    public ArrayList<VoiceHandler> voiceHandlers= new ArrayList<VoiceHandler>();
    //</editor-fold>
   
    public ModPircbot() {
        super();
        mainBot = this;
        setName("ooo");
    }
    public void addModule(Handler h) {
        if(!modules.contains(h)) {
            modules.add(h);
            h.register(this);
        }
        else
            System.err.println("Attempting to reload existing module: "+h.getClass().getName());
    }
    public void addMainBot(ModPircbot b) {
        mainBot = b;
    }
    //<editor-fold desc="All on*() functions" defaultstate="collapsed">
    //<editor-fold desc="Override all callback functions to call all handler functions" defaultstate="collapsed">
    @Override
    protected void onAction(String sender, String login, String hostname, String target, String action) {
        for(ActionHandler ah : actionHandlers) 
            ah.onAction(sender, login, hostname, target, action);
    }
    @Override
    protected void onChannelInfo(String channel, int userCount, String topic) {
        for(ChannelInfoHandler ih : channelInfoHandlers)
            ih.onChannelInfo(channel, userCount, topic);
    }
    @Override
    protected void onConnect() {
        for(ConnectHandler ch : connectHandlers)
            ch.onConnect();
    }
    /*
    @Override
    protected void onDccChatRequest(String sourceNick, String sourceLogin, String sourceHostname, long address, int port) {
        for(DccChatHandler dch : dccChatHandlers)
            dch.onDccChatRequest(sourceNick, sourceLogin, sourceHostname, address, port);
    }
    @Override
    protected void onDccSendRequest(String sourceNick, String sourceLogin, String sourceHostname, String filename, long address, int port, int size) {
        for(DccSendHandler dsh : dccSendHandlers) 
            dsh.onDccSendRequest(sourceNick, sourceLogin, sourceHostname, filename, address, port, size);
    }
    */
    protected void onDeHalfop(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
        if(useDefaultModeParsing)
            for(DeHalfOpHandler dhh : deHalfopHandlers)
                dhh.onDeHalfop(channel, sourceNick, sourceLogin, sourceHostname, recipient);
    }
    @Override
    protected void onDeop(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
        if(useDefaultModeParsing)
            for(DeOpHandler doh : deOpHandlers)
                doh.onDeop(channel, sourceNick, sourceLogin, sourceHostname, recipient);
    }
    @Override
    protected void onDeVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
        if(useDefaultModeParsing)
            for(DeVoiceHandler dvh : deVoiceHandlers)
                dvh.onDeVoice(channel, sourceNick, sourceLogin, sourceHostname, recipient);
    }
    @Override
    protected void onDisconnect() {
        for(DisconnectHandler dh : disconnectHandlers)
            dh.onDisconnect();
    }
    @Override
    protected void onFileTransferFinished(DccFileTransfer transfer, Exception e) {
        for(FileTransferFinishedHandler ftfh : fileTransferFinishedHandlers)
            ftfh.onFileTransferFinished(transfer, e);
    }
    @Override
    protected void onFinger(String sourceNick, String sourceLogin, String sourceHostname, String target) {
        for(FingerHandler fh : fingerHandlers)
            fh.onFinger(sourceNick, sourceLogin, sourceHostname, target);
    }
    protected void onHalfOp(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
        for(HalfOpHandler hh : halfOpHandlers) 
            hh.onHalfOp(channel, sourceNick, sourceLogin, sourceHostname, recipient);
    }
    @Override
    protected void onIncomingChatRequest(DccChat chat) {
        for(IncomingChatReqHandler icrh : incomingChatReqHandlers)
            icrh.onIncomingChatRequest(chat);
    }
    @Override
    protected void onIncomingFileTransfer(DccFileTransfer transfer) {
        for(IncomingFileTransferHander ifth : incomingFileTransferHandlers)
            ifth.onIncomingFileTransfer(transfer);
    }
    @Override 
    protected void onInvite(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String channel) {
        for(InviteHandler ih : inviteHandlers)
            ih.onInvite(targetNick, sourceNick, sourceLogin, sourceHostname, channel);
    }
    @Override
    protected void onJoin(String channel, String sender, String login, String hostname) {
        for(JoinHandler jh : joinHandlers)
            jh.onJoin(channel, sender, login, hostname);
    }
    @Override
    protected void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {
        for(KickHandler kh : kickHandlers)
            kh.onKick(channel, kickerNick, kickerLogin, kickerHostname, recipientNick, reason);
    }
    @Override
    protected void onMessage(String channel, String sender, String login, String hostname, String message) {
        for(MessageHandler mh : messageHandlers)
            mh.onMessage(channel, sender, login, hostname, message);
    }
    //</editor-fold>
    @Override
    protected void onMode(String channel, String sourceNick, String sourceLogin, String sourceHostname, String mode) {
        String[] modeArray = mode.split("\\s+");
        String modes = modeArray[0];
        int paramNum = 1;
        if(!useDefaultModeParsing) {
            String addOrRemove = "+";
            for(int i=0; i<modes.length(); i++) {
                if(modes.charAt(i)=='+')
                    addOrRemove = "+";
                else if(mode.charAt(i)=='-') 
                    addOrRemove = "-";
                else {
                    //Then this is a mode character
                    if(supportedModes.containsKey(modes.substring(i,i+1))) {
                        switch(supportedModes.get(modes.substring(i,i+1))) {
                            case 0:
                                //Always has a param
                                onSingleMode(channel, sourceNick, sourceLogin, sourceHostname, addOrRemove+modes.substring(i,i+1), modeArray[paramNum]);
                                paramNum++;
                                break;
                            case 1:
                                onSingleMode(channel, sourceNick, sourceLogin, sourceHostname, addOrRemove+modes.substring(i,i+1), modeArray[paramNum]);
                                paramNum++;
                                break;
                            case 2:
                                if(addOrRemove.equals("+")) {
                                    onSingleMode(channel, sourceNick, sourceLogin, sourceHostname, addOrRemove+modes.substring(i,i+1), modeArray[paramNum]);
                                    paramNum++;
                                }
                                else
                                    onSingleMode(channel, sourceNick, sourceLogin, sourceHostname, addOrRemove+modes.substring(i,i+1), "");
                                break;
                            default:
                                onSingleMode(channel, sourceNick, sourceLogin, sourceHostname, addOrRemove+modes.substring(i,i+1), "");
                                break;
                        }
                    }
                }
            }
        }
        else {
            for(ChannelModeHandler mh : channelModeHandlers) {
                mh.onMode(channel, sourceNick, sourceLogin, sourceHostname, mode);
            }
        }
    }
    //<editor-fold desc="More callback stuff" defaultstate="collapsed">
    @Override
    protected void onNickChange(String oldNick, String login, String hostname, String newNick) {
        for(NickChangeHandler nch : nickChangeHandlers)
            nch.onNickChange(oldNick, login, hostname, newNick);
    }
    @Override
    protected void onNotice(String sourceNick, String sourceLogin, String sourceHostname, String target, String notice) {
        for(NoticeHandler nh : noticeHandlers)
            nh.onNotice(sourceNick, sourceLogin, sourceHostname, target, notice);
    }
    @Override
    protected void onOp(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
        if(useDefaultModeParsing)
            for(OpHandler oh : opHandlers)
                oh.onOp(channel, sourceNick, sourceLogin, sourceHostname, recipient);
    }
    @Override
    protected void onPart(String channel, String sender, String login, String hostname) {
        for(PartHandler ph : partHandlers)
            ph.onPart(channel, sender, login, hostname);
    }
    @Override
    protected void onPing(String sourceNick, String sourceLogin, String sourceHostname, String target, String pingValue) {
        for(PingHandler ph : pingHandlers)
            ph.onPing(sourceNick, sourceLogin, sourceHostname, target, pingValue);
    }
    @Override
    protected void onPrivateMessage(String sender, String login, String hostname, String message) {
        for(PrivateMessageHandler pmh : privateMessageHandlers)
            pmh.onPrivateMessage(sender, login, hostname, message);
    }
    @Override
    protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {
        for(QuitHandler qh : quitHandlers)
            qh.onQuit(sourceNick, sourceLogin, sourceHostname, reason);
    }
    @Override
    protected void onRemoveChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {
        if(useDefaultModeParsing)
            for(RemoveChannelBanHandler rcbh : removeChannelBanHandlers)
                rcbh.onRemoveChannelBan(channel, sourceNick, sourceLogin, sourceHostname, hostmask);
    }
    @Override
    protected void onRemoveChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {
        if(useDefaultModeParsing)
            for(RemoveChannelKeyHandler rckh : removeChannelKeyHandlers) 
                rckh.onRemoveChannelKey(channel, sourceNick, sourceLogin, sourceHostname, key);
    }
    @Override
    protected void onRemoveChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(RemoveChannelLimitHandler rclh : removeChannelLimitHandlers)
                rclh.onRemoveChannelLimit(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onRemoveInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(RemoveInviteHandler rih : removeInviteHandlers)
                rih.onRemoveInviteOnly(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onRemoveModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(RemoveModeratedHandler rmh : removeModeratedHandlers)
                rmh.onRemoveModerated(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onRemoveNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(RemoveNoExternalMessagesHandler rnemh : removeNoExternalMessagesHandlers)
                rnemh.onRemoveNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onRemovePrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(RemovePrivateHandler rph : removePrivateHandlers)
                rph.onRemovePrivate(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onRemoveSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(RemoveSecretHandler rsh : removeSecretHandlers)
                rsh.onRemoveSecret(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onRemoveTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(RemoveTopicProtectionHandler rtph : removeTopicProtectionHandlers)
                rtph.onRemoveTopicProtection(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onServerPing(String response) {
        for(ServerPingHandler sph : serverPingHandlers)
            sph.onServerPing(response);
    }
    //</editor-fold>
    protected void onSingleMode(String channel, String sourceNick, String sourceLogin, String sourceHostname, String mode, String param) {
        for(ChannelModeHandler mh : channelModeHandlers) {
            String modeString;
            if(param.equals(""))
                modeString = mode;
            else
                modeString = mode + " " + param;
            mh.onMode(channel, sourceNick, sourceLogin, sourceHostname, modeString);
        }
        if(mode.substring(0,1).equals("+")) {
            //Then we are setting the mode
            char modeChar = mode.charAt(1);
            switch(modeChar) {
                case 'q' :
                    //Owner
                    System.out.printf("Owner\n");
                    //Not handled for now
                    break;
                case 'a' :
                    //Protected/Admin/Superop
                    System.out.printf("Admin\n");
                    //Not handled for now
                    break;
                case 'o' :
                    //Full op
                    System.out.printf("Op\n");
                    for(OpHandler oh : opHandlers) {
                        oh.onOp(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                //<editor-fold desc="Repeat for all common/standard modes" defaultstate="collapsed">
                case 'h' :
                    //Half op
                    for(HalfOpHandler hh : halfOpHandlers) {
                        hh.onHalfOp(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                case 'v' :
                    //Voice
                    for(VoiceHandler vh : voiceHandlers) {
                        vh.onVoice(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                case 'k' :
                    //Channel key
                    for(SetChannelKeyHandler kh : setChannelKeyHandlers) {
                        kh.onSetChannelKey(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                case 'l' :
                    //Channel limit
                    for(SetChannelLimitHandler lh : setChannelLimitHandlers) {
                        //Mark: fix this later to have error handling for parseint
                        lh.onSetChannelLimit(channel, sourceNick, sourceLogin, sourceHostname, Integer.parseInt(param));
                    }
                    break;
                case 'i' :
                    //invite only
                    for(SetInviteOnlyHandler ih : setInviteOnlyHandlers) {
                        ih.onSetInviteOnly(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 'm' :
                    //moderated
                    for(SetModeratedHandler mh : setModeratedHandlers) {
                        mh.onSetModerated(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 'n' :
                    //no external
                    for(SetNoExternalMessagesHandler nh : setNoExternalMessagesHandlers) {
                        nh.onSetNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 'p' :
                    //private
                    for(SetPrivateHandler ph : setPrivateHandlers) {
                        ph.onSetPrivate(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 's' :
                    //secret
                    for(SetSecretHandler sh : setSecretHandlers) {
                        sh.onSetSecret(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 't' :
                    //topic protect
                    for(SetTopicProtectionHandler th : setTopicProtectionHandlers) {
                        th.onSetTopicProtection(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                //</editor-fold>
                default : 
                    //unhandled mode by pircbot
                    break;
            }
        }
        else {
            //Then we are unsetting the mode
            char modeChar = mode.charAt(1);
            switch(modeChar) {
                case 'q' :
                    //Owner
                    //Not handled for now
                    break;
                case 'a' :
                    //Protected/Admin/Superop
                    //Not handled for now
                    break;
                case 'o' :
                    //Full op
                    for(DeOpHandler oh : deOpHandlers) {
                        oh.onDeop(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                //<editor-fold desc="Repeat for all common/standard modes" defaultstate="collapsed">
                case 'h' :
                    //Half op
                    for(DeHalfOpHandler hh : deHalfopHandlers) {
                        hh.onDeHalfop(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                case 'v' :
                    //Voice
                    for(DeVoiceHandler vh : deVoiceHandlers) {
                        vh.onDeVoice(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                case 'k' :
                    //Channel key
                    for(RemoveChannelKeyHandler kh : removeChannelKeyHandlers) {
                        kh.onRemoveChannelKey(channel, sourceNick, sourceLogin, sourceHostname, param);
                    }
                    break;
                case 'l' :
                    //Channel limit
                    for(RemoveChannelLimitHandler lh : removeChannelLimitHandlers) {
                        //Mark: fix this later to have error handling for parseint
                        lh.onRemoveChannelLimit(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 'i' :
                    //invite only
                    for(RemoveInviteHandler ih : removeInviteHandlers) {
                        ih.onRemoveInviteOnly(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 'm' :
                    //moderated
                    for(RemoveModeratedHandler mh : removeModeratedHandlers) {
                        mh.onRemoveModerated(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 'n' :
                    //no external
                    for(RemoveNoExternalMessagesHandler nh : removeNoExternalMessagesHandlers) {
                        nh.onRemoveNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 'p' :
                    //private
                    for(RemovePrivateHandler ph : removePrivateHandlers) {
                        ph.onRemovePrivate(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 's' :
                    //secret
                    for(RemoveSecretHandler sh : removeSecretHandlers) {
                        sh.onRemoveSecret(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                case 't' :
                    //topic protect
                    for(RemoveTopicProtectionHandler th : removeTopicProtectionHandlers) {
                        th.onRemoveTopicProtection(channel, sourceNick, sourceLogin, sourceHostname);
                    }
                    break;
                //</editor-fold>
                default : 
                    //unhandled mode by pircbot
                    break;
            }
        }
    }
    
    //<editor-fold desc="Even more callbacks" defaultstate="collapsed">
    @Override
    protected void onServerResponse(int code, String response) {
        for(ServerResponseHandler rh : serverResponseHandlers) 
            rh.onServerResponse(code, response);
        if(code == ModPircbot.RPL_ISUPPORT) {
            //If the reply is the ISUPPORT string, parse out the different mode
            //categories:
            //First type always has a parameter (adds or removes something from list)
            //Second type changes a setting and always has a para meter
            //Third type only has a parameter when set
            //Fourth type never has a parameter
            //
            //Example: 
            //Example ISUPPORT STRING...returns added to avoid wrap
            //AWAYLEN=200 CALLERID=g CASEMAPPING=rfc1459 CHANMODES=Ibegw,k,FHJLfjl,ABCDKMNOPQRSTcimnprstuz
            //CHANTYPES=# CHARSET=ascii ELIST=MU ESILENCE EXCEPTS=e EXTBAN=,ABCNOQRSTcmprsz FNC INVEX=I KICKLEN=255
            //:are supported by this server
            
            int chanModesBegin = response.indexOf("CHANMODES");
            if(chanModesBegin >= 0) {
                String[] chanModes = response.substring(chanModesBegin).split("\\s+")[0].split(",");
                for(int i=0; i<4 && i<chanModes.length; i++) {
                    String modes = chanModes[i];
                    for(int j=0; j<modes.length(); j++) {
                        String mode = modes.substring(j, j+1);
                        supportedModes.put(mode, Integer.valueOf(i));
                    }
                }
            }
            else {
                useDefaultModeParsing = true;
            }
        }
    }
    @Override
    protected void onSetChannelBan(String channel, String sourceNick, String sourceLogin, String sourceHostname, String hostmask) {
        if(useDefaultModeParsing)
            for(SetChannelBanHandler cbh : setChannelBanHandlers)
                cbh.onSetChannelBan(channel, sourceNick, sourceLogin, sourceHostname, hostmask);
    }
    @Override
    protected void onSetChannelKey(String channel, String sourceNick, String sourceLogin, String sourceHostname, String key) {
        if(useDefaultModeParsing)
            for(SetChannelKeyHandler ckh : setChannelKeyHandlers)
                ckh.onSetChannelKey(channel, sourceNick, sourceLogin, sourceHostname, key);
    }
    @Override
    protected void onSetChannelLimit(String channel, String sourceNick, String sourceLogin, String sourceHostname, int limit) {
        if(useDefaultModeParsing)
            for(SetChannelLimitHandler clh : setChannelLimitHandlers)
                clh.onSetChannelLimit(channel, sourceNick, sourceLogin, sourceHostname, limit);
    }
    @Override
    protected void onSetInviteOnly(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(SetInviteOnlyHandler ioh : setInviteOnlyHandlers)
                ioh.onSetInviteOnly(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onSetModerated(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(SetModeratedHandler mh : setModeratedHandlers)
                mh.onSetModerated(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onSetNoExternalMessages(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(SetNoExternalMessagesHandler nemh : setNoExternalMessagesHandlers)
                nemh.onSetNoExternalMessages(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onSetPrivate(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(SetPrivateHandler ph : setPrivateHandlers)
                ph.onSetPrivate(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onSetSecret(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(SetSecretHandler sh : setSecretHandlers)
                sh.onSetSecret(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onSetTopicProtection(String channel, String sourceNick, String sourceLogin, String sourceHostname) {
        if(useDefaultModeParsing)
            for(SetTopicProtectionHandler tph : setTopicProtectionHandlers)
                tph.onSetTopicProtection(channel, sourceNick, sourceLogin, sourceHostname);
    }
    @Override
    protected void onTime(String sourceNick, String sourceLogin, String sourceHostname, String target) {
        for(TimeHandler th : timeHandlers)
            th.onTime(sourceNick, sourceLogin, sourceHostname, target);
    }
    @Override
    protected void onTopic(String channel, String topic, String setBy, long date, boolean changed) {
        for(TopicHandler th : topicHandlers)
            th.onTopic(channel, topic, setBy, date, changed);
    }
    @Override
    protected void onUserList(String channel, User[] users) {
        for(UserListHandler ulh : userListHandlers)
            ulh.onUserList(channel, users);
    }
    @Override
    protected void onUserMode(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String mode) {
        for(UserModeHandler umh : userModeHandlers)
            umh.onUserMode(targetNick, sourceNick, sourceLogin, sourceHostname, mode);
    }
    @Override
    protected void onVersion(String sourceNick, String sourceLogin, String sourceHostname, String target) {
        for(VersionHandler vh : versionHandlers)
            vh.onVersion(sourceNick, sourceLogin, sourceHostname, target);
    }
    @Override
    protected void onVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
        if(useDefaultModeParsing)
            for(VoiceHandler vh : voiceHandlers)
                vh.onVoice(channel, sourceNick, sourceLogin, sourceHostname, recipient);
    }
    //</editor-fold>
    //</editor-fold>
    
    //<editor-fold desc="All bot-server related commands" defaultstate="collapsed">
    //Whoever wrote this apparently thought they should make everything final.
    //Jerks
    public void myBan(String channel, String hostmask)  {
        if(mainBot!=this) 
            mainBot.myBan(channel, hostmask);
        else
            ban(channel, hostmask);
    }
    public void myConnect(String hostname) throws IOException, IrcException {
        if(mainBot!=this)
            mainBot.myConnect(hostname);
        else
            connect(hostname);
    }
    public void myConnect(String hostname, int port) throws IOException, IrcException{
        if(mainBot!=this)
            mainBot.myConnect(hostname, port);
        else
            connect(hostname, port);
    }
    public void myConnect(String hostname, int port, String password) throws IOException, IrcException{
        if(mainBot!=this)
            mainBot.myConnect(hostname, port, password);
        else
            connect(hostname, port, password);
    }
    public DccChat myDccSendChatRequest(String nick, int timeout) {
        if(mainBot!=this)
            return mainBot.myDccSendChatRequest(nick, timeout);
        else
            return dccSendChatRequest(nick, timeout);
    }
    public DccFileTransfer myDccSendFile(File file, String nick, int timeout) {
        if(mainBot!=this)
            return mainBot.myDccSendFile(file, nick, timeout);
        else
            return dccSendFile(file, nick, timeout);
    }
    public void myDeOp(String channel, String nick) {
        if(mainBot!=this)
            mainBot.myDeOp(channel, nick);
        else
            deOp(channel, nick);
    }
    public void myDeVoice(String channel, String nick) {
        if(mainBot!=this) 
            mainBot.myDeOp(channel, nick);
        else
            deVoice(channel, nick);
    }
    public void myDisconnect() {
        if(mainBot!=this) 
            mainBot.myDisconnect();
        else
            disconnect();
    }
    //Dispose intentionally omitted
    //Equals omitted
    public String[] myGetChannels() {
        if(mainBot!=this)
            return mainBot.myGetChannels();
        else
            return getChannels();
    }
    public InetAddress myGetDccInetAddress() {
        if(mainBot!=this)
            return mainBot.myGetDccInetAddress();
        else
            return getInetAddress();
    }
    public int[] myGetDccPorts() {
        if(mainBot!=this)
            return mainBot.myGetDccPorts();
        else
            return getDccPorts();
    }
    public String myGetEncoding() {
        if(mainBot!=this)
            return mainBot.myGetEncoding();
        else
            return getEncoding();
    }
    public String myGetFinger() {
        if(mainBot!=this)
            return mainBot.myGetFinger();
        else
            return getFinger();
    }
    public InetAddress myGetInetAddress() {
        if(mainBot!=this)
            return mainBot.myGetInetAddress();
        else
            return getInetAddress();
    }
    public String myGetLogin() {
        if(mainBot!=this)
            return mainBot.myGetLogin();
        else
            return getLogin();
    }
    public int myGetMaxLineLength() {
        if(mainBot!=this)
            return mainBot.myGetMaxLineLength();
        else
            return getMaxLineLength();
    }
    public long myGetMessageDelay() {
        if(mainBot!=this)
            return mainBot.myGetMessageDelay();
        else
            return getMessageDelay();
    }
    public String myGetName() {
        if(mainBot!=this)
            return mainBot.myGetName();
        else
            return getName();
    }
    public String myGetNick() {
        if(mainBot!=this)
            return mainBot.myGetNick();
        else
            return getNick();
    }
    public int myGetOutgoingQueueSize() {
        if(mainBot!=this)
            return mainBot.myGetOutgoingQueueSize();
        else
            return getOutgoingQueueSize();
    }
    public String myGetPassword() {
        if(mainBot!=this)
            return mainBot.myGetPassword();
        else
            return getPassword();
    }
    public int myGetPort() {
        if(mainBot!=this)
            return mainBot.myGetPort();
        else
            return getPort();
    }
    public String myGetServer() {
        if(mainBot!=this)
            return mainBot.myGetServer();
        else
            return getServer();
    }
    public User[] myGetUsers(String channel) {
        if(mainBot!=this)
            return mainBot.myGetUsers(channel);
        else
            return getUsers(channel);
    }
    public String myGetVersion() {
        if(mainBot!=this)
            return mainBot.myGetVersion();
        else
            return getVersion();
    }
    public void myIdentify(String password) {
        if(mainBot!=this)
            mainBot.myIdentify(password);
        else
            identify(password);
    }
    public boolean myIsConnected() {
        if(mainBot!=this)
            return mainBot.myIsConnected();
        else
            return isConnected();
    }
    public void myJoinChannel(String channel) {
        if(mainBot!=this)
            mainBot.myJoinChannel(channel);
        else
            joinChannel(channel);
    }
    public void myJoinChannel(String channel, String key) {
        if(mainBot!=this)
            mainBot.myJoinChannel(channel, key);
        else
            joinChannel(channel, key);
    }
    public void myKick(String channel, String nick) {
        if(mainBot!=this)
            mainBot.myKick(channel, nick);
        else
            kick(channel, nick);
    }
    public void myKick(String channel, String nick, String reason) {
        if(mainBot!=this)
            mainBot.myKick(channel, nick, reason);
        else
            kick(channel, nick, reason);
    }
    public void myListChannels() {
        if(mainBot!=this)
            mainBot.myListChannels();
        else
            listChannels();
    }
    public void myListChannels(String parameters) {
        if(mainBot!=this)
            mainBot.myListChannels(parameters);
        else
            listChannels(parameters);
    }
    public void myLog(String line) {
        if(mainBot!=this)
            mainBot.myLog(line);
        else
            log(line);
    }
    public void myOp(String channel, String nick) {
        if(mainBot!=this) 
            mainBot.myOp(channel, nick);
        else
            op(channel, nick);
    }
    public void myPartChannel(String channel) {
        if(mainBot!=this)
            mainBot.myPartChannel(channel);
        else
            partChannel(channel);
    }
    public void myPartChannel(String channel, String reason) {
        if(mainBot!=this)
            mainBot.myPartChannel(channel, reason);
        else
            partChannel(channel, reason);
    }
    public void myQuitServer() {
        if(mainBot!=this)
            mainBot.myQuitServer();
        else
            quitServer();
    }
    public void myQuitServer(String reason) {
        if(mainBot!=this)
            mainBot.myQuitServer(reason);
        else
            quitServer(reason);
    }
    public void myReconnect() throws IOException, IrcException{
        if(mainBot!=this)
            mainBot.myReconnect();
        else
            reconnect();
    }
    //</editor-fold>
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        ModPircbot b = new ModPircbot();
        try {
            b.connect("irc.dhirc.com", 6667);
        }
        catch(Exception e) {
            System.out.println(e.getClass().getName()+": "+e.getMessage());
        }
    }
}
